To make MongoDB database manipulation easy, we can use the Mongoose NPM package to make working with MongoDB databases easier.
In this article, we’ll look at how to use Mongoose to manipulate our MongoDB database.
Removing Foreign Documents
If we remove foreign documents, then when we try to reference a linked foreign document, it’ll return null
.
For instance, if we have:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = connection.model('Story', storySchema);
const Person = connection.model('Person', personSchema);
const author = new Person({
_id: new Types.ObjectId(),
name: 'James Smith',
age: 50
});
await author.save();
const story1 = new Story({
title: 'Mongoose Story',
author: author._id
});
await story1.save();
await Person.deleteMany({ name: 'James Smith' });
const story = await Story.findOne({ title: 'Mongoose Story' }).populate('author');
console.log(story)
}
run();
We created a Story
document that is linked to an Author
.
Then we deleted the Person
with the name 'James Smith'
.
Now when we retrieve the latest value of the story with the author
with populate
, we’ll see that story
is null
.
Field Selection
We can select a few fields instead of selecting all the fields when we call populate
.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = connection.model('Story', storySchema);
const Person = connection.model('Person', personSchema);
const author = new Person({
_id: new Types.ObjectId(),
name: 'James Smith',
age: 50
});
await author.save();
const story1 = new Story({
title: 'Mongoose Story',
author: author._id
});
await story1.save();
const story = await Story.findOne({ title: 'Mongoose Story' })
.populate('author', 'name')
.exec();
console.log(story)
}
run();
We save the author
and story1
documents into our database.
Then we call findOne
to get the story document with the author
and the name
properties.
Populating Multiple Paths
If we call populate
multiple times, then only the last one will take effect.
Query Conditions and Other Options
The populate
method can accept query conditions.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = connection.model('Story', storySchema);
const Person = connection.model('Person', personSchema);
const author = new Person({
_id: new Types.ObjectId(),
name: 'James Smith',
age: 50
});
await author.save();
const fan = new Person({
_id: new Types.ObjectId(),
name: 'Fan Smith',
age: 50
});
await fan.save();
const story1 = new Story({
title: 'Mongoose Story',
author: author._id,
fans: [fan._id]
});
await story1.save();
const story = await Story.findOne({ title: 'Mongoose Story' })
.populate({
path: 'fans',
match: { age: { $gte: 21 } },
select: 'name -_id'
})
.exec();
console.log(story.fans)
}
run();
We add a Person
entry to the fans
array.
Then when we call populate
with an object that finds all the fans with age
greater than or equal to 21, we should get our fan entry.
The select
property has a string that lets us select the name
field but not the _id
as indicated by the -
sign before the _id
.
So the console log should show [{“name”:”Fan Smith”}]
.
Conclusion
We can join documents with various options with Mongoose.